/*
 * BlackLightning.PluginLib.OptionMessage
 * Andy Tidball
 * 
 * Project: Black Lightning Plugin Library
 * Copyright: GNU General Public License
 */

using System;
using BLLib.Configuration;

namespace BlackLightning.PluginLib {
	/// <summary>
	/// A message sent to Black Lightning to deal with an option.
	/// </summary>
	[Serializable]
	public class OptionMessage : Message {
		// member data
		private string _Name; // the name of the option in question

		/// <summary>
		/// Creates a new OptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option in question.</param>
		public OptionMessage(string Name) {
			_Name = Name;
		}

		/// <summary>
		/// Gets the name of the option in question.
		/// </summary>
		public string Name {
			get {
				return _Name;
			}
		}
	}

	/// <summary>
	/// A message sent to Black Lightning to tell it to display the options dialog.
	/// </summary>
	[Serializable]
	public class ShowOptionsMessage : Message {
	}

	/// <summary>
	/// A message sent to Black Lightning to register an option.
	/// </summary>
	[Serializable]
	public class RegisterOptionMessage : OptionMessage {
		// member data
		private object _DefaultValue = null;  // the option's default value
		private Type   _ValueType    = null;  // the type of the Option's values
		private string _Description  = null;  // the option's description
		private string _Category     = null;  // the name of the option's category
		private bool   _Hidden       = false; // whether or not the option is hidden from the user
		private bool   _ReadOnly     = false; // whether or not the option is read only
		private Type   _Editor       = null;  // the UI editor used to edit the option's values
		private Type   _Converter    = null;  // the converter used to convert the option's values to and from strings
		private string _EncryptKey   = null;  // the key to use to encrypt and decrypt the option's value

		/// <summary>
		/// Creates a new RegisterOptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		public RegisterOptionMessage(string Name, Type ValueType, object DefaultValue)
			: this(Name, ValueType, DefaultValue, null) {
		}

		/// <summary>
		/// Creates a new RegisterOptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		public RegisterOptionMessage(string Name, Type ValueType, object DefaultValue, string Description)
			: this(Name, ValueType, DefaultValue, Description, null) {
		}

		/// <summary>
		/// Creates a new RegisterOptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		public RegisterOptionMessage(string Name, Type ValueType, object DefaultValue, string Description, string Category)
			: this(Name, ValueType, DefaultValue, Description, Category, false) {
		}

		/// <summary>
		/// Creates a new RegisterOptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		public RegisterOptionMessage(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden)
			: this(Name, ValueType, DefaultValue, Description, Category, Hidden, false) {
		}

		/// <summary>
		/// Creates a new RegisterOptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		/// <param name="ReadOnly">Whether or not the option is read only.</param>
		public RegisterOptionMessage(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden, bool ReadOnly)
			: this(Name, ValueType, DefaultValue, Description, Category, Hidden, ReadOnly, null) {
		}

		/// <summary>
		/// Creates a new RegisterOptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		/// <param name="ReadOnly">Whether or not the option is read only.</param>
		/// <param name="EncryptKey">The key to use to encrypt and decrypt the option's value while stored on disk, or null to not encrypt the value.  Only used if ValueType == typeof(string).</param>
		public RegisterOptionMessage(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden, bool ReadOnly, string EncryptKey)
			: this(Name, ValueType, DefaultValue, Description, Category, Hidden, ReadOnly, EncryptKey, null) {
		}

		/// <summary>
		/// Creates a new RegisterOptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		/// <param name="ReadOnly">Whether or not the option is read only.</param>
		/// <param name="EncryptKey">The key to use to encrypt and decrypt the option's value while stored on disk, or null to not encrypt the value.  Only used if ValueType == typeof(string).</param>
		/// <param name="Editor">The UITypeEditor-derived type to use as a UI editor for the option's type.</param>
		public RegisterOptionMessage(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden, bool ReadOnly, string EncryptKey, Type Editor)
			: this(Name, ValueType, DefaultValue, Description, Category, Hidden, ReadOnly, EncryptKey, Editor, null) {
		}

		/// <summary>
		/// Creates a new RegisterOptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option.</param>
		/// <param name="ValueType">The type of the option's values.</param>
		/// <param name="DefaultValue">The option's default value.</param>
		/// <param name="Description">The option's description.</param>
		/// <param name="Category">The name of the option's category.</param>
		/// <param name="Hidden">Whether or not the option is hidden from the user.</param>
		/// <param name="ReadOnly">Whether or not the option is read only.</param>
		/// <param name="EncryptKey">The key to use to encrypt and decrypt the option's value while stored on disk, or null to not encrypt the value.  Only used if ValueType == typeof(string).</param>
		/// <param name="Editor">The UITypeEditor-derived type to use as a UI editor for the option's type.</param>
		/// <param name="Converter">The TypeConverter-derived type to use to convert the option's values to and from strings.</param>
		public RegisterOptionMessage(string Name, Type ValueType, object DefaultValue, string Description, string Category, bool Hidden, bool ReadOnly, string EncryptKey, Type Editor, Type Converter)
			: base(Name) {
			if (ValueType.IsMarshalByRef) {
				throw new ArgumentException("The given value type '" + ValueType.Name + "' marshals by reference (probably inherits from MarshalByRefObject) and cannot be used as an option's value type.");
			}

			_ValueType    = ValueType;
			_DefaultValue = DefaultValue;
			_Description  = Description;
			_Category     = Category;
			_Hidden       = Hidden;
			_ReadOnly     = ReadOnly;
			_Editor       = Editor;
			_Converter    = Converter;
			_EncryptKey   = EncryptKey;
		}

		/// <summary>
		/// Gets the type of the option's values.
		/// </summary>
		public Type ValueType {
			get {
				return _ValueType;
			}
		}

		/// <summary>
		/// Gets or sets the option's description.
		/// </summary>
		public string Description {
			get {
				return _Description;
			}
		}

		/// <summary>
		/// Gets or sets the option's default value.
		/// </summary>
		public object DefaultValue {
			get {
				return _DefaultValue;
			}
		}

		/// <summary>
		/// Gets or sets the name of the category that the option will appear in.
		/// </summary>
		public string Category {
			get {
				return _Category;
			}
		}

		/// <summary>
		/// Gets or sets whether or not the option is hidden from the user.
		/// </summary>
		public bool Hidden {
			get {
				return _Hidden;
			}
		}

		/// <summary>
		/// Gets or sets whether or not the option is read only.
		/// </summary>
		public bool ReadOnly {
			get {
				return _ReadOnly;
			}
		}

		/// <summary>
		/// Gets or sets the type of the UI editor used to edit values of the option.
		/// </summary>
		public Type Editor {
			get {
				return _Editor;
			}
		}

		/// <summary>
		/// Gets or sets type of the converter that will be used to convert the option's values to and from strings.  The type must provide a default constructor.
		/// </summary>
		public Type Converter {
			get {
				return _Converter;
			}
		}

		/// <summary>
		/// Gets the key to use to encrypt and decrypt the option's value.
		/// </summary>
		public string EncryptKey {
			get {
				return _EncryptKey;
			}
		}

		/// <summary>
		/// Gets an initializer that can be used to initialize an Option with the settings in this Message.
		/// </summary>
		/// <param name="ValueIndices">The value indices that the Option will store values at.</param>
		/// <returns>An OptionInitializer that can be used to initialize an Option.</returns>
		internal OptionInitializer GetInitializer(int[] ValueIndices) {
			return new OptionInitializer(_ValueType, _DefaultValue, _Description, _Category, _Hidden, _ReadOnly, _EncryptKey, _Editor, _Converter, ValueIndices);
		}
	}

	/// <summary>
	/// A message sent to Black Lightning to unregister an option.
	/// </summary>
	[Serializable]
	public class UnregisterOptionMessage : OptionMessage {
		/// <summary>
		/// Creates a new UnregisterOptionMessage.
		/// </summary>
		/// <param name="Name">The name of the option to unregister.</param>
		public UnregisterOptionMessage(string Name)
			: base(Name) {
		}
	}

	/// <summary>
	/// A message sent to Black Lightning to change the value of an option.
	/// </summary>
	[Serializable]
	public class ChangeOptionValueMessage : OptionMessage {
		// member data
		private object _Value; // the value to assign to the option

		/// <summary>
		/// Creates a new ChangeOptionValueMessage.
		/// </summary>
		/// <param name="Name">The name of the option whose value to change.</param>
		/// <param name="Value">The value to assign to the option.</param>
		public ChangeOptionValueMessage(string Name, object Value)
			: base(Name) {
			_Value = Value;
		}

		/// <summary>
		/// Gets the value to assign to the option.
		/// </summary>
		public object Value {
			get {
				return _Value;
			}
		}
	}

	/// <summary>
	/// A message sent by Black Lightning to a module, plugin, or login client when one of its option's values changes.
	/// </summary>
	[Serializable]
	public class OptionValueChangedMessage : OptionMessage {
		// member data
		private object _OldValue; // the option's old value
		private object _NewValue; // the option's new value

		/// <summary>
		/// Creates a new OptionValueChangedMessage.
		/// </summary>
		/// <param name="Name">The name of the option whose value changed.</param>
		/// <param name="OldValue">The option's old value.</param>
		/// <param name="NewValue">The option's new value.</param>
		public OptionValueChangedMessage(string Name, object OldValue, object NewValue)
			: base(Name) {
			_OldValue = OldValue;
			_NewValue = NewValue;
		}

		/// <summary>
		/// The option's old value.
		/// </summary>
		public object OldValue {
			get {
				return _OldValue;
			}
		}

		/// <summary>
		/// The option's new value.
		/// </summary>
		public object NewValue {
			get {
				return _NewValue;
			}
		}
	}
}
